<template>
  <view class="fu-upload">
    <!-- 上传列表 -->
    <view 
      v-if="showFileList"
      class="fu-upload__list"
    >
      <view 
        v-for="(file, index) in fileList" 
        :key="index"
        class="fu-upload__item"
      >
        <!-- 图片预览 -->
        <image 
          v-if="listType === 'picture'"
          class="fu-upload__image"
          :src="file.url" 
          mode="aspectFill"
          @click="handlePreview(file)"
        />
        
        <!-- 文件信息 -->
        <view class="fu-upload__info">
          <text class="fu-upload__name">{{ file.name }}</text>
          <text 
            v-if="file.status === 'uploading'"
            class="fu-upload__progress"
          >
            {{ file.percentage }}%
          </text>
        </view>
        
        <!-- 删除按钮 -->
        <text 
          v-if="!disabled"
          class="fu-upload__remove"
          @click="handleRemove(file, index)"
        >×</text>
      </view>
    </view>
    
    <!-- 上传按钮 -->
    <view 
      class="fu-upload__trigger"
      :class="[
        `fu-upload__trigger--${listType}`,
        { 
          'fu-upload__trigger--disabled': disabled || (limit && fileList.length >= limit)
        }
      ]"
      @click="!disabled && (!limit || fileList.length < limit) && handleClick()"
    >
      <slot>
        <view v-if="listType === 'picture'" class="fu-upload__picture">
          <text class="fu-upload__icon">+</text>
          <text class="fu-upload__text">{{ uploadText }}</text>
        </view>
        <view v-else class="fu-upload__default">
          <text class="fu-upload__icon">+</text>
          <text class="fu-upload__text">{{ uploadText }}</text>
        </view>
      </slot>
    </view>
  </view>
</template>

<script>
/**
 * fu-upload 上传组件
 * @description 文件上传组件，支持图片和文件上传
 * @property {Array} fileList - 已上传的文件列表
 * @property {String} action - 上传的地址
 * @property {String} listType - 文件列表的类型，可选值：text/picture
 * @property {Boolean} disabled - 是否禁用
 * @property {Number} limit - 最大允许上传个数
 * @property {String} accept - 接受上传的文件类型
 * @property {Object} headers - 设置上传的请求头部
 * @property {String} uploadText - 上传按钮文字
 * @event {Function} change - 文件状态改变时的回调
 * @event {Function} success - 文件上传成功时的回调
 * @event {Function} error - 文件上传失败时的回调
 * @event {Function} exceed - 文件超出个数限制时的回调
 * @event {Function} remove - 文件被删除时的回调
 */
export default {
  name: 'fu-upload',
  props: {
    fileList: {
      type: Array,
      default: () => []
    },
    action: {
      type: String,
      required: true
    },
    listType: {
      type: String,
      default: 'text',
      validator: value => ['text', 'picture'].includes(value)
    },
    disabled: {
      type: Boolean,
      default: false
    },
    limit: {
      type: Number,
      default: 0
    },
    accept: {
      type: String,
      default: '*'
    },
    headers: {
      type: Object,
      default: () => ({})
    },
    uploadText: {
      type: String,
      default: '点击上传'
    },
    showFileList: {
      type: Boolean,
      default: true
    }
  },
  emits: ['update:fileList', 'change', 'success', 'error', 'exceed', 'remove'],
  methods: {
    handleClick() {
      if (this.disabled) return
      
      // 选择文件
      uni.chooseFile({
        count: this.limit - this.fileList.length || 1,
        type: 'all',
        extension: this.accept.split(','),
        success: (res) => {
          const files = res.tempFiles
          
          if (this.limit && this.fileList.length + files.length > this.limit) {
            this.$emit('exceed', files, this.fileList)
            return
          }
          
          files.forEach(file => {
            this.upload(file)
          })
        }
      })
    },
    upload(file) {
      const uploadFile = {
        name: file.name,
        url: '',
        status: 'uploading',
        percentage: 0
      }
      
      const newFileList = [...this.fileList, uploadFile]
      this.$emit('update:fileList', newFileList)
      this.$emit('change', { file: uploadFile, fileList: newFileList })
      
      uni.uploadFile({
        url: this.action,
        filePath: file.path,
        name: 'file',
        header: this.headers,
        success: (res) => {
          const response = JSON.parse(res.data)
          uploadFile.status = 'success'
          uploadFile.url = response.url
          uploadFile.percentage = 100
          
          this.$emit('success', response, uploadFile, newFileList)
          this.$emit('change', { file: uploadFile, fileList: newFileList })
        },
        fail: (err) => {
          uploadFile.status = 'error'
          
          this.$emit('error', err, uploadFile, newFileList)
          this.$emit('change', { file: uploadFile, fileList: newFileList })
        }
      })
    },
    handleRemove(file, index) {
      const newFileList = this.fileList.filter((_, i) => i !== index)
      this.$emit('update:fileList', newFileList)
      this.$emit('remove', file, newFileList)
    },
    handlePreview(file) {
      if (file.url) {
        uni.previewImage({
          urls: this.fileList.map(item => item.url),
          current: file.url
        })
      }
    }
  }
}
</script>

<style lang="scss" scoped>
@import '../../styles/mixins.scss';

.fu-upload {
  &__list {
    margin-bottom: 20rpx;
  }
  
  &__item {
    display: flex;
    align-items: center;
    padding: 20rpx;
    background-color: #f7f8fa;
    border-radius: var(--fu-radius-base);
    margin-bottom: 20rpx;
    
    &:last-child {
      margin-bottom: 0;
    }
  }
  
  &__image {
    width: 100rpx;
    height: 100rpx;
    border-radius: var(--fu-radius-base);
    margin-right: 20rpx;
  }
  
  &__info {
    flex: 1;
    min-width: 0;
  }
  
  &__name {
    display: block;
    font-size: var(--fu-font-size-base);
    color: var(--fu-text-color);
    margin-bottom: 8rpx;
    @include text-ellipsis;
  }
  
  &__progress {
    font-size: var(--fu-font-size-sm);
    color: var(--fu-text-color-secondary);
  }
  
  &__remove {
    padding: 0 20rpx;
    font-size: 40rpx;
    color: var(--fu-text-color-secondary);
    cursor: pointer;
    
    &:active {
      color: var(--fu-text-color);
    }
  }
  
  &__trigger {
    display: inline-block;
    cursor: pointer;
    
    &--picture {
      width: 200rpx;
      height: 200rpx;
      background-color: #f7f8fa;
      border-radius: var(--fu-radius-base);
      border: 2rpx dashed var(--fu-border-color);
      
      .fu-upload__picture {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }
    }
    
    &--disabled {
      cursor: not-allowed;
      opacity: 0.5;
      pointer-events: none;
    }
  }
  
  &__default {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20rpx 30rpx;
    background-color: #f7f8fa;
    border-radius: var(--fu-radius-base);
    border: 2rpx dashed var(--fu-border-color);
  }
  
  &__icon {
    font-size: 40rpx;
    color: var(--fu-text-color-secondary);
    margin-right: 10rpx;
  }
  
  &__text {
    font-size: var(--fu-font-size-base);
    color: var(--fu-text-color);
  }
}
</style> 